home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / frasrc19.zip / BIGNUMA.ASM < prev    next >
Assembly Source File  |  1995-02-03  |  88KB  |  2,476 lines

  1. ; bignuma.asm - asm routines for bignumbers
  2. ; far pointer version
  3. ; Wesley Loewer's Big Numbers.        (C) 1994, Wesley B. Loewer
  4.  
  5. ; IMPORTANT!!!  The following routines assume that all the bignumber arrays
  6. ; were allocated from the same far segment.  This allows the routines to
  7. ; switch the DS register to that segment and treat everything then as a
  8. ; near pointer.  If that array is not in this segment, then copy it into
  9. ; an array that is.
  10.  
  11. ; See BIGNUMC.C for further documentation.
  12.  
  13. .MODEL medium, c
  14.  
  15. ifdef ??version ; for TASM
  16.    ideal
  17. TYPEDEF bn_t far ptr byte
  18.    masm
  19.    masm51
  20.    quirks
  21. ; invoke w/ one arg
  22. invoke macro a,b
  23.    call a, b
  24. endm
  25. ; invoke with 2 args
  26. invoke2 macro a,b,c
  27.    call a, b, c
  28. endm
  29. extern equ extrn
  30.  
  31. else
  32.  
  33. bn_t TYPEDEF far ptr byte   ; far pointer to bignumber array
  34.  
  35. endif
  36.  
  37. .DATA
  38.  
  39. extern cpu:word
  40. extern bnlength:word, rlength:word;
  41.  
  42. .CODE
  43. .8086
  44.  
  45. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  46. ; r = 0
  47. clear_bn   PROC USES di, r:bn_t
  48.         les     di, r                   ; load pointer in es:di for stos
  49.         mov     cx, bnlength
  50.  
  51.         cmp     cpu, 386                ; check cpu
  52.         je      short use_32_bit        ; use faster 32 bit code if possible
  53.  
  54.         sub     ax, ax                  ; clear ax
  55.         shr     cx, 1                   ; 1 byte = 1/2 word
  56.         rep     stosw                   ; clear r, word at a time
  57.  
  58.         jmp     bottom
  59.  
  60. use_32_bit:
  61. .386
  62.         sub     eax, eax                ; clear eax
  63.         shr     cx, 2                   ; 1 byte = 1/4 word
  64.         rep     stosd                   ; clear r, dword at a time
  65.  
  66. bottom:
  67. .8086
  68.         mov     dx, es                  ; return r in dx:ax
  69.         mov     ax, word ptr r
  70.         ret
  71.  
  72. clear_bn   ENDP
  73.  
  74. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  75. ; r = max positive value
  76. max_bn   PROC USES di, r:bn_t
  77.         les     di, r                   ; load pointer in es:di for stos
  78.         mov     cx, bnlength
  79.  
  80.         cmp     cpu, 386                ; check cpu
  81.         je      short use_32_bit        ; use faster 32 bit code if possible
  82.  
  83.         mov     ax, 0FFFFh              ; set ax to max value
  84.         shr     cx, 1                   ; 1 byte = 1/2 word
  85.         rep     stosw                   ; max out r, word at a time
  86.  
  87.         jmp     bottom
  88.  
  89. use_32_bit:
  90. .386
  91.         mov     eax, 0FFFFFFFFh         ; set eax to max value
  92.         shr     cx, 2                   ; 1 byte = 1/4 word
  93.         rep     stosd                   ; max out r, dword at a time
  94.  
  95. bottom:
  96. .8086
  97.         ; when the above stos is finished, di points to the byte past the end
  98.         dec     di                          ; find sign bit in msb
  99.         mov     byte ptr es:[di], 7Fh       ; turn off the sign bit
  100.  
  101.         mov     dx, es                  ; return r in dx:ax
  102.         mov     ax, word ptr r
  103.         ret
  104.  
  105. max_bn   ENDP
  106.  
  107. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  108. ; r = n
  109. copy_bn   PROC USES di si, r:bn_t, n:bn_t
  110.         les     di, r                   ; load pointer in es:di for movs
  111.         mov     ax, ds                  ; save ds for later
  112.         mov     cx, bnlength
  113.  
  114.         cmp     cpu, 386                ; check cpu
  115.         je      short use_32_bit        ; use faster 32 bit code if possible
  116.  
  117.         lds     si, n                   ; load pointer in ds:si for movs
  118.         shr     cx, 1                   ; 1 byte = 1/2 word
  119.         rep     movsw                   ; copy word at a time
  120.         jmp     bottom
  121.  
  122. use_32_bit:
  123. .386
  124.         lds     si, n                   ; load pointer in ds:si for movs
  125.         shr     cx, 2                   ; 1 byte = 1/4 word
  126.         rep     movsd                   ; copy dword at a time
  127.  
  128. bottom:
  129. .8086
  130.         mov     ds, ax                  ; restore ds
  131.         mov     dx, es                  ; return r in dx:ax
  132.         mov     ax, word ptr r
  133.         ret
  134.  
  135. copy_bn   ENDP
  136.  
  137. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  138. ; n1 != n2 ?
  139. ; RETURNS: if n1 == n2 returns 0
  140. ;          if n1 > n2 returns a positive (steps left to go when mismatch occured)
  141. ;          if n1 < n2 returns a negative (steps left to go when mismatch occured)
  142. cmp_bn   PROC USES di, n1:bn_t, n2:bn_t
  143.  
  144.         mov     cx, bnlength
  145.  
  146.         push    ds                      ; save DS
  147.         mov     di, word ptr n2
  148.         lds     bx, n1                  ; load pointers
  149.         add     bx, cx                  ; point to end of bignumbers
  150.         add     di, cx                  ; where the msb is
  151.  
  152.         cmp     cpu, 386                ; check cpu
  153.         je      short use_32_bit        ; use faster 32 bit code if possible
  154.  
  155.         shr     cx, 1                   ; byte = 1/2 word
  156.         mov     dx, cx                  ; keep a copy of cx
  157. top_loop_16:
  158.         sub     bx, 2                   ; decrement to previous word
  159.         sub     di, 2
  160.         mov     ax, [bx]                ; load n1
  161.         cmp     ax, [di]                ; compare to n2
  162.         jne     bottom                  ; don't match
  163.         loop    top_loop_16
  164.         jmp     match
  165.  
  166. use_32_bit:
  167. .386
  168.         shr     cx, 2                   ; byte = 1/4 dword
  169.         mov     dx, cx                  ; keep a copy of cx
  170. top_loop_32:
  171.         sub     bx, 4                   ; decrement to previous dword
  172.         sub     di, 4
  173.         mov     eax, [bx]               ; load n1
  174.         cmp     eax, [di]               ; compare to n2
  175.         jne     bottom                  ; don't match
  176.         loop    top_loop_32
  177.         jmp     match
  178.  
  179. bottom:
  180. .8086
  181. ; flags are still set from last cmp
  182. ; if cx == dx, then most significant part didn't match, use signed comparison
  183. ; else the decimals didn't match, use unsigned comparison
  184.         lahf                            ; load results of last cmp
  185.         cmp     cx, dx                  ; did they differ on very first cmp
  186.         jne     not_first_step          ; no
  187.  
  188.         sahf                            ; yes
  189.         jg      n1_bigger               ; signed comparison
  190.         jmp     n2_bigger
  191.  
  192. not_first_step:
  193.         sahf
  194.         ja      n1_bigger               ; unsigned comparison
  195.  
  196. n2_bigger:
  197.         neg     cx                      ; make it negative
  198. n1_bigger:                              ; leave it positive
  199. match:                                  ; leave it zero
  200.         mov     ax, cx
  201.         pop     ds                      ; restore DS
  202.         ret
  203.  
  204. cmp_bn   ENDP
  205.  
  206. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  207. ; r < 0 ?
  208. ; returns 1 if negative, 0 if positive or zero
  209. is_bn_neg   PROC n:bn_t
  210.  
  211.         ; for a one-pass routine like this, don't bother with ds
  212.         les     bx, n                       ; find sign bit
  213.         add     bx, bnlength
  214.         dec     bx                          ; here it is
  215.         mov     al, es:[bx]                 ; got it
  216.         and     al, 80h                     ; check the sign bit
  217.         rol     al, 1                       ; rotate sign big to bit 0
  218.         sub     ah, ah                      ; clear upper ax
  219.         ret
  220.  
  221. is_bn_neg   ENDP
  222.  
  223. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  224. ; n != 0 ?
  225. ; RETURNS: if n != 0 returns 1
  226. ;          else returns 0
  227. is_bn_not_zero   PROC n:bn_t
  228.  
  229.         mov     cx, bnlength
  230.         mov     ax, ds                  ; save DS
  231.         lds     bx, n                   ; load pointers with DS
  232.  
  233.         cmp     cpu, 386                ; check cpu
  234.         je      short use_32_bit        ; use faster 32 bit code if possible
  235.  
  236.         shr     cx, 1                   ; byte = 1/2 word
  237. top_loop_16:
  238.         cmp     word ptr [bx], 0        ; compare to n to 0
  239.         jnz     bottom                  ; not zero
  240.         add     bx, 2                   ; increment to next word
  241.         loop    top_loop_16
  242.         jmp     bottom
  243.  
  244. use_32_bit:
  245. .386
  246.         shr     cx, 2                   ; byte = 1/4 dword
  247. top_loop_32:
  248.         cmp     dword ptr [bx], 0       ; compare to n to 0
  249.         jnz     bottom                  ; not zero
  250.         add     bx, 4                   ; increment to next dword
  251.         loop    top_loop_32
  252.         jmp     bottom
  253.  
  254. bottom:
  255. .8086
  256.         mov     ds, ax                  ; restore DS
  257.         ; if cx is zero, then n was zero
  258.         mov     ax, cx
  259.         ret
  260.  
  261. is_bn_not_zero   ENDP
  262.  
  263. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  264. ; r = n1 + n2
  265. add_bn   PROC USES di si, r:bn_t, n1:bn_t, n2:bn_t
  266.  
  267.         mov     cx, bnlength
  268.         push    ds                      ; save ds
  269.         mov     di, word ptr n1         ; load pointers ds:di
  270.         mov     si, word ptr n2         ;               ds:si
  271.         lds     bx, r                   ;               ds:bx
  272.  
  273.         cmp     cpu, 386                ; check cpu
  274.         je      short use_32_bit        ; use faster 32 bit code if possible
  275.  
  276.         shr     cx, 1                   ; byte = 1/2 word
  277.         clc                             ; clear carry flag
  278.  
  279. top_loop_16:
  280.         mov     ax, [di]                ; n1
  281.         adc     ax, [si]                ; n1+n2
  282.         mov     [bx], ax                ; r = n1+n2
  283.  
  284.                                         ; inc does not change carry flag
  285.         inc     di                      ; add  di, 2
  286.         inc     di
  287.         inc     si                      ; add  si, 2
  288.         inc     si
  289.         inc     bx                      ; add  bx, 2
  290.         inc     bx
  291.  
  292.         loop    top_loop_16
  293.         jmp     short bottom
  294.  
  295. use_32_bit:
  296. .386
  297.  
  298.         shr     cx, 2                   ; byte = 1/4 double word
  299.         clc                             ; clear carry flag
  300.  
  301. top_loop_32:
  302.         mov     eax, [di]               ; n1
  303.         adc     eax, [si]               ; n1+n2
  304.         mov     [bx], eax               ; r = n1+n2
  305.  
  306.         lahf                            ; save carry flag
  307.         add     di, 4                   ; increment by double word size
  308.         add     si, 4
  309.         add     bx, 4
  310.     sahf                            ; restore carry flag
  311.  
  312.         loop    top_loop_32
  313.  
  314. bottom:
  315. .8086
  316.         mov     dx, ds                  ; return r in dx:ax
  317.         pop     ds                      ; restore ds
  318.         mov     ax, word ptr r
  319.         ret
  320. add_bn   ENDP
  321.  
  322. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  323. ; r += n
  324. add_a_bn   PROC USES di, r:bn_t, n:bn_t
  325.  
  326.         mov     cx, bnlength
  327.         push    ds
  328.         mov     di, word ptr n          ; load pointers ds:di
  329.         lds     bx, r                   ;               ds:bx
  330.  
  331.         cmp     cpu, 386                ; check cpu
  332.         je      short use_32_bit        ; use faster 32 bit code if possible
  333.  
  334.         shr     cx, 1                   ; byte = 1/2 word
  335.         clc                             ; clear carry flag
  336.  
  337. top_loop_16:
  338.         mov     ax, [di]                ; n
  339.         adc     [bx], ax                ; r += n
  340.  
  341.                                         ; inc does not change carry flag
  342.         inc     di                      ; add  di, 2
  343.         inc     di
  344.         inc     bx                      ; add  di, 2
  345.         inc     bx
  346.  
  347.         loop    top_loop_16
  348.         jmp     short bottom
  349.  
  350. use_32_bit:
  351. .386
  352.  
  353.         shr     cx, 2                   ; byte = 1/4 double word
  354.         clc                             ; clear carry flag
  355.  
  356. top_loop_32:
  357.         mov     eax, [di]               ; n
  358.         adc     [bx], eax               ; r += n
  359.  
  360.         lahf                            ; save carry flag
  361.         add     di, 4                   ; increment by double word size
  362.         add     bx, 4
  363.     sahf                            ; restore carry flag
  364.  
  365.         loop    top_loop_32
  366.  
  367. bottom:
  368. .8086
  369.         mov     dx, ds                  ; return r in dx:ax
  370.         pop     ds                      ; restore ds
  371.         mov     ax, word ptr r
  372.         ret
  373. add_a_bn   ENDP
  374.  
  375. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  376. ; r = n1 - n2
  377. sub_bn   PROC USES di si, r:bn_t, n1:bn_t, n2:bn_t
  378.  
  379.         mov     cx, bnlength
  380.         push    ds
  381.         mov     di, word ptr n1         ; load pointers ds:di
  382.         mov     si, word ptr n2         ;               ds:si
  383.         lds     bx, r                   ;               ds:bx
  384.  
  385.         cmp     cpu, 386                ; check cpu
  386.         je      short use_32_bit        ; use faster 32 bit code if possible
  387.  
  388.         shr     cx, 1                   ; byte = 1/2 word
  389.         clc                             ; clear carry flag
  390.  
  391. top_loop_16:
  392.         mov     ax, [di]                ; n1
  393.         sbb     ax, [si]                ; n1-n2
  394.         mov     [bx], ax                ; r = n1-n2
  395.  
  396.                                         ; inc does not change carry flag
  397.         inc     di                      ; add  di, 2
  398.         inc     di
  399.         inc     si                      ; add  si, 2
  400.         inc     si
  401.         inc     bx                      ; add  bx, 2
  402.         inc     bx
  403.  
  404.         loop    top_loop_16
  405.         jmp     short bottom
  406.  
  407. use_32_bit:
  408. .386
  409.  
  410.         shr     cx, 2                   ; byte = 1/4 double word
  411.         clc                             ; clear carry flag
  412.  
  413. top_loop_32:
  414.         mov     eax, [di]               ; n1
  415.         sbb     eax, [si]               ; n1-n2
  416.         mov     [bx], eax               ; r = n1-n2
  417.  
  418.         lahf                            ; save carry flag
  419.         add     di, 4                   ; increment by double word size
  420.         add     si, 4
  421.         add     bx, 4
  422.     sahf                            ; restore carry flag
  423.  
  424.         loop    top_loop_32
  425.  
  426. bottom:
  427. .8086
  428.  
  429.         mov     dx, ds                  ; return r in dx:ax
  430.         pop     ds                      ; restore ds
  431.         mov     ax, word ptr r
  432.         ret
  433. sub_bn   ENDP
  434.  
  435. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  436. ; r -= n
  437. sub_a_bn   PROC USES di, r:bn_t, n:bn_t
  438.  
  439.         mov     cx, bnlength
  440.         push    ds
  441.         mov     di, word ptr n          ; load pointers ds:di
  442.         lds     bx, r                   ;               ds:bx
  443.  
  444.         cmp     cpu, 386                ; check cpu
  445.         je      short use_32_bit        ; use faster 32 bit code if possible
  446.  
  447.         shr     cx, 1                   ; byte = 1/2 word
  448.         clc                             ; clear carry flag
  449.  
  450. top_loop_16:
  451.         mov     ax, [di]                ; n
  452.         sbb     [bx], ax                ; r -= n
  453.  
  454.                                         ; inc does not change carry flag
  455.         inc     di                      ; add  di, 2
  456.         inc     di
  457.         inc     bx                      ; add  di, 2
  458.         inc     bx
  459.  
  460.         loop    top_loop_16
  461.         jmp     short bottom
  462.  
  463. use_32_bit:
  464. .386
  465.  
  466.         shr     cx, 2                   ; byte = 1/4 double word
  467.         clc                             ; clear carry flag
  468.  
  469. top_loop_32:
  470.         mov     eax, [di]               ; n
  471.         sbb     [bx], eax               ; r -= n
  472.  
  473.         lahf                            ; save carry flag
  474.         add     di, 4                   ; increment by double word size
  475.         add     bx, 4
  476.     sahf                            ; restore carry flag
  477.  
  478.         loop    top_loop_32
  479.  
  480. bottom:
  481. .8086
  482.  
  483.         mov     dx, ds                  ; return r in dx:ax
  484.         pop     ds                      ; restore ds
  485.         mov     ax, word ptr r
  486.         ret
  487. sub_a_bn   ENDP
  488.  
  489. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  490. ; r = -n
  491. neg_bn   PROC USES di, r:bn_t, n:bn_t
  492.         mov     cx, bnlength
  493.         push    ds
  494.         mov     di, word ptr n          ; load pointers ds:di
  495.         lds     bx, r                   ;               ds:bx
  496.  
  497.         cmp     cpu, 386
  498.         je      short use_32_bit        ; use faster 32 bit code if possible
  499.  
  500.         shr     cx, 1                   ; byte = 1/2 word
  501.  
  502. top_loop_16:
  503.         mov     ax, [di]
  504.         neg     ax
  505.         mov     [bx], ax
  506.         jc      short no_more_carry_16  ; notice the "reverse" logic here
  507.  
  508.         add     di, 2                   ; increment by word size
  509.         add     bx, 2
  510.  
  511.         loop    top_loop_16
  512.         jmp     short bottom
  513.  
  514. no_more_carry_16:
  515.         add     di, 2
  516.         add     bx, 2
  517.         loop    top_loop_no_more_carry_16   ; jump down
  518.         jmp     short bottom
  519.  
  520. top_loop_no_more_carry_16:
  521.         mov     ax, [di]
  522.         not     ax
  523.         mov     [bx], ax
  524.  
  525.         add     di, 2
  526.         add     bx, 2
  527.  
  528.         loop    top_loop_no_more_carry_16
  529.         jmp     short bottom
  530.  
  531. use_32_bit:
  532. .386
  533.         shr     cx, 2                   ; byte = 1/4 dword
  534.  
  535. top_loop_32:
  536.         mov     eax, [di]
  537.         neg     eax
  538.         mov     [bx], eax
  539.         jc     short no_more_carry_32   ; notice the "reverse" logic here
  540.  
  541.         add     di, 4                   ; increment by double word size
  542.         add     bx, 4
  543.  
  544.         loop    top_loop_32
  545.         jmp     short bottom
  546.  
  547. no_more_carry_32:
  548.         add     di, 4                   ; increment by double word size
  549.         add     bx, 4
  550.         loop    top_loop_no_more_carry_32   ; jump down
  551.         jmp     short bottom
  552.  
  553. top_loop_no_more_carry_32:
  554.         mov     eax, [di]
  555.         not     eax
  556.         mov     [bx], eax
  557.  
  558.         add     di, 4                   ; increment by double word size
  559.         add     bx, 4
  560.  
  561.         loop    top_loop_no_more_carry_32
  562.  
  563. bottom:
  564. .8086
  565.  
  566.         mov     dx, ds                  ; return r in dx:ax
  567.         pop     ds                      ; restore ds
  568.         mov     ax, word ptr r
  569.         ret
  570. neg_bn   ENDP
  571.  
  572. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  573. ; r *= -1
  574. neg_a_bn   PROC r:bn_t
  575.         mov     cx, bnlength
  576.         push    ds
  577.         lds     bx, r                   ; ds:bx
  578.  
  579.         cmp     cpu, 386
  580.         je      short use_32_bit        ; use faster 32 bit code if possible
  581.  
  582.         shr     cx, 1                   ; byte = 1/2 word
  583.  
  584. top_loop_16:
  585.         neg     word ptr [bx]
  586.         jc      short no_more_carry_16  ; notice the "reverse" logic here
  587.  
  588.         add     bx, 2
  589.  
  590.         loop    top_loop_16
  591.         jmp     short bottom
  592.  
  593. no_more_carry_16:
  594.         add     bx, 2
  595.         loop    top_loop_no_more_carry_16   ; jump down
  596.         jmp     short bottom
  597.  
  598. top_loop_no_more_carry_16:
  599.         not     word ptr [bx]
  600.  
  601.         add     bx, 2
  602.  
  603.         loop    top_loop_no_more_carry_16
  604.         jmp     short bottom
  605.  
  606. use_32_bit:
  607. .386
  608.         shr     cx, 2                   ; byte = 1/4 dword
  609.  
  610. top_loop_32:
  611.         neg     dword ptr [bx]
  612.         jc     short no_more_carry_32   ; notice the "reverse" logic here
  613.  
  614.         add     bx, 4
  615.  
  616.         loop    top_loop_32
  617.         jmp     short bottom
  618.  
  619. no_more_carry_32:
  620.         add     bx, 4
  621.         loop    top_loop_no_more_carry_32   ; jump down
  622.         jmp     short bottom
  623.  
  624. top_loop_no_more_carry_32:
  625.         not     dword ptr [bx]
  626.  
  627.         add     bx, 4
  628.  
  629.         loop    top_loop_no_more_carry_32
  630.  
  631. bottom:
  632. .8086
  633.  
  634.         mov     dx, ds                  ; return r in dx:ax
  635.         pop     ds                      ; restore ds
  636.         mov     ax, word ptr r
  637.         ret
  638. neg_a_bn   ENDP
  639.  
  640. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  641. ; r = 2*n
  642. double_bn   PROC USES di, r:bn_t, n:bn_t
  643.         mov     cx, bnlength
  644.         push    ds
  645.         mov     di, word ptr n          ; load pointers ds:di
  646.         lds     bx, r                   ;               ds:bx
  647.  
  648.         cmp     cpu, 386
  649.         je      short use_32_bit        ; use faster 32 bit code if possible
  650.  
  651.         shr     cx, 1                   ; byte = 1/2 word
  652.         clc
  653.  
  654. top_loop_16:
  655.         mov     ax, [di]
  656.         rcl     ax, 1                   ; rotate with carry left
  657.         mov     [bx], ax
  658.  
  659.                                         ; inc does not change carry flag
  660.         inc     di                      ; add  di, 2
  661.         inc     di
  662.         inc     bx                      ; add bx, 2
  663.         inc     bx
  664.  
  665.         loop    top_loop_16
  666.         jmp     short bottom
  667.  
  668. use_32_bit:
  669. .386
  670.         shr     cx, 2                   ; byte = 1/4 dword
  671.         clc                             ; clear carry flag
  672.  
  673. top_loop_32:
  674.         mov     eax, [di]
  675.         rcl     eax, 1                  ; rotate with carry left
  676.         mov     [bx], eax
  677.  
  678.         lahf                            ; save carry flag
  679.         add     di, 4                   ; increment by double word size
  680.         add     bx, 4
  681.     sahf                            ; restore carry flag
  682.  
  683.         loop    top_loop_32
  684.  
  685. bottom:
  686. .8086
  687.  
  688.         mov     dx, ds                  ; return r in dx:ax
  689.         pop     ds                      ; restore ds
  690.         mov     ax, word ptr r
  691.         ret
  692. double_bn   ENDP
  693.  
  694. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  695. ; r *= 2
  696. double_a_bn   PROC r:bn_t
  697.         mov     cx, bnlength
  698.         push    ds
  699.         lds     bx, r                   ;               ds:bx
  700.  
  701.         cmp     cpu, 386
  702.         je      short use_32_bit        ; use faster 32 bit code if possible
  703.  
  704.         shr     cx, 1                   ; byte = 1/2 word
  705.         clc
  706.  
  707. top_loop_16:
  708.         rcl     word ptr [bx], 1        ; rotate with carry left
  709.  
  710.                                         ; inc does not change carry flag
  711.         inc     bx                      ; add  bx, 2
  712.         inc     bx
  713.  
  714.         loop    top_loop_16
  715.         jmp     short bottom
  716.  
  717. use_32_bit:
  718. .386
  719.         shr     cx, 2                   ; byte = 1/4 dword
  720.         clc                             ; clear carry flag
  721.  
  722. top_loop_32:
  723.         rcl     dword ptr [bx], 1       ; rotate with carry left
  724.  
  725.         lahf                            ; save carry flag
  726.         add     bx, 4
  727.     sahf                            ; restore carry flag
  728.  
  729.         loop    top_loop_32
  730.  
  731. bottom:
  732. .8086
  733.  
  734.         mov     dx, ds                  ; return r in dx:ax
  735.         pop     ds                      ; restore ds
  736.         mov     ax, word ptr r
  737.         ret
  738. double_a_bn   ENDP
  739.  
  740. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  741. ; r = n/2
  742. half_bn   PROC USES di, r:bn_t, n:bn_t
  743.         mov     cx, bnlength
  744.         push    ds
  745.         mov     di, word ptr n          ; load pointers ds:di
  746.         lds     bx, r                   ;               ds:bx
  747.         add     di, cx                  ; start with msb
  748.         add     bx, cx
  749.  
  750.         cmp     cpu, 386
  751.         je      short use_32_bit        ; use faster 32 bit code if possible
  752.  
  753.         shr     cx, 1                   ; byte = 1/2 word
  754.  
  755.         ; handle the first step with sar, the rest with rcr
  756.         sub     di, 2
  757.         sub     bx, 2
  758.  
  759.         mov     ax, [di]
  760.         sar     ax, 1                   ; shift arithmetic right
  761.         mov     [bx], ax
  762.  
  763.         loop    top_loop_16
  764.         jmp     short bottom
  765.  
  766.  
  767. top_loop_16:
  768.                                         ; inc does not change carry flag
  769.         dec     di                      ; sub  di, 2
  770.         dec     di
  771.         dec     bx                      ; sub bx, 2
  772.         dec     bx
  773.  
  774.         mov     ax, [di]
  775.         rcr     ax, 1                   ; rotate with carry right
  776.         mov     [bx], ax
  777.  
  778.         loop    top_loop_16
  779.         jmp     short bottom
  780.  
  781. use_32_bit:
  782. .386
  783.         shr     cx, 2                   ; byte = 1/4 dword
  784.  
  785.         sub     di, 4                   ; decrement by double word size
  786.         sub     bx, 4
  787.  
  788.         mov     eax, [di]
  789.         sar     eax, 1                  ; shift arithmetic right
  790.         mov     [bx], eax
  791.  
  792.         loop    top_loop_32
  793.         jmp     short bottom
  794.  
  795. top_loop_32:
  796.         lahf                            ; save carry flag
  797.         sub     di, 4                   ; decrement by double word size
  798.         sub     bx, 4
  799.     sahf                            ; restore carry flag
  800.  
  801.         mov     eax, [di]
  802.         rcr     eax, 1                  ; rotate with carry right
  803.         mov     [bx], eax
  804.  
  805.         loop    top_loop_32
  806.  
  807. bottom:
  808. .8086
  809.  
  810.         mov     dx, ds                  ; return r in dx:ax
  811.         pop     ds                      ; restore ds
  812.         mov     ax, word ptr r
  813.         ret
  814. half_bn   ENDP
  815.  
  816. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  817. ; r /= 2
  818. half_a_bn   PROC r:bn_t
  819.         mov     cx, bnlength
  820.         push    ds
  821.         lds     bx, r                   ;               ds:bx
  822.         add     bx, cx
  823.  
  824.  
  825.         cmp     cpu, 386
  826.         je      short use_32_bit        ; use faster 32 bit code if possible
  827.  
  828.         shr     cx, 1                   ; byte = 1/2 word
  829.  
  830.         ; handle the first step with sar, the rest with rcr
  831.         sub     bx, 2
  832.  
  833.         sar     word ptr [bx], 1        ; shift arithmetic right
  834.  
  835.         loop    top_loop_16
  836.         jmp     short bottom
  837.  
  838.  
  839. top_loop_16:
  840.                                         ; inc does not change carry flag
  841.         dec     bx                      ; sub bx, 2
  842.         dec     bx
  843.  
  844.         rcr     word ptr [bx], 1        ; rotate with carry right
  845.  
  846.         loop    top_loop_16
  847.         jmp     short bottom
  848.  
  849. use_32_bit:
  850. .386
  851.         shr     cx, 2                   ; byte = 1/4 dword
  852.  
  853.         sub     bx, 4                   ; decrement by double word size
  854.  
  855.         sar     dword ptr [bx], 1       ; shift arithmetic right
  856.  
  857.         loop    top_loop_32
  858.         jmp     short bottom
  859.  
  860. top_loop_32:
  861.         lahf                            ; save carry flag
  862.         sub     di, 4                   ; decrement by double word size
  863.         sub     bx, 4
  864.     sahf                            ; restore carry flag
  865.  
  866.         rcr     dword ptr [bx], 1       ; rotate with carry right
  867.  
  868.         loop    top_loop_32
  869.  
  870. bottom:
  871. .8086
  872.  
  873.         mov     dx, ds                  ; return r in dx:ax
  874.         pop     ds                      ; restore ds
  875.         mov     ax, word ptr r
  876.         ret
  877. half_a_bn   ENDP
  878.  
  879.  
  880. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  881. ; r = n1 * n2
  882. ; Note: r will be a double wide result, 2*bnlength
  883. ;       n1 and n2 can be the same pointer
  884. ; SIDE-EFFECTS: n1 and n2 are changed to their absolute values
  885. ;
  886. unsafe_full_mult_bn   PROC USES di si, r:bn_t, n1:bn_t, n2:bn_t
  887. LOCAL sign1:byte, sign2:byte, samevar:byte, \
  888.       i:word, j:word, steps:word, doublesteps:word, carry_steps:word, \
  889.       n1p: ptr byte, n2p: ptr byte
  890.  
  891. ; This routine uses near variables and far pointers together in the
  892. ; inner-most loops.  Therefore, there is little to gain by setting DS
  893. ; to the far segment.  Instead, set ES to the far segment and use segment
  894. ; overrides where necessary.
  895.  
  896. ; By forcing the bignumber to be positive and keeping track of the sign
  897. ; bits separately, quite a few multiplies are saved.
  898.  
  899.         ; set the ES register
  900.         les     bx, n1                      ; check for sign bits
  901.         add     bx, bnlength
  902.         dec     bx
  903.         mov     al, es:[bx]
  904.         and     al, 80h                     ; check the sign bit
  905.         mov     sign1, al
  906.         jz      already_pos1
  907.         invoke  neg_a_bn, n1
  908. already_pos1:
  909.  
  910. ; Test to see if n1 and n2 are the same variable.  It would be better to
  911. ; use square_bn(), but it could happen.
  912.  
  913.         mov     samevar, 1                  ; assume they are the same
  914.         mov     bx, word ptr n2
  915.         cmp     bx, word ptr n1             ; are they the same?
  916.         je      already_pos2                ; if so, it has already been negated
  917.         mov     samevar, 0                  ; they weren't the same after all
  918.  
  919.         add     bx, bnlength
  920.         dec     bx
  921.         mov     al, es:[bx]
  922.         and     al, 80h                     ; check the sign bit
  923.         mov     sign2, al
  924.         jz      already_pos2
  925.         invoke  neg_a_bn, n2
  926. already_pos2:
  927.  
  928. ; in the following loops, the following pointers are used
  929. ;   n1p, n2p = points to the part of n1, n2 being used
  930. ;   di = points to part of doublebignumber used in outer loop
  931. ;   si = points to part of doublebignumber used in inner loop
  932. ;   bx = points to part of doublebignumber for carry flag loop
  933.  
  934.         cmp     cpu, 386                ; check cpu
  935.         je      use_32_bit              ; use faster 32 bit code if possible
  936.  
  937.         mov     ax, word ptr n1         ; load pointers
  938.         mov     n1p, ax
  939.  
  940.         mov     dx, bnlength            ; set outer loop counter
  941.         shr     dx, 1                   ; byte = 1/2 word
  942.         mov     steps, dx               ; save in steps
  943.         mov     i, dx
  944.         shl     dx, 1                   ; double steps
  945.  
  946.         sub     ax, ax                  ; clear ax
  947.         mov     cx, dx                  ; size of doublebignumber (r) in words
  948.         mov     di, word ptr r          ; es already set
  949.         rep     stosw                   ; initialize r to 0
  950.  
  951.         sub     dx, 2                   ; only 2*s-2 steps are really needed
  952.         mov     doublesteps, dx
  953.         mov     carry_steps, dx
  954.         mov     di, word ptr r
  955.         mov     si, di                  ; both si and di are used here
  956.  
  957. top_outer_loop_16:
  958.         mov     ax, word ptr n2         ; set n2p pointer
  959.         mov     n2p, ax
  960.         mov     ax, steps               ; set inner loop counter
  961.         mov     j, ax
  962.  
  963. top_inner_loop_16:
  964.         mov     bx, n1p
  965.         mov     ax, es:[bx]
  966.         mov     bx, n2p
  967.         mul     word ptr es:[bx]
  968.  
  969.         mov     bx, si
  970.         add     es:[bx], ax             ; add low word
  971.         inc     bx                      ; increase by size of word
  972.         inc     bx
  973.         adc     es:[bx], dx             ; add high word
  974.         jnc     no_more_carry_16        ; carry loop not necessary
  975.  
  976.         mov     cx, carry_steps         ; how many till end of double big number
  977.         jcxz    no_more_carry_16
  978.         add     bx, 2                   ; move pointer to next word
  979.  
  980.         ; loop until no more carry or until end of double big number
  981. top_carry_loop_16:
  982.         add     word ptr es:[bx], 1     ; use add, not inc
  983.         jnc     no_more_carry_16
  984.         add     bx, 2                   ; increase by size of word
  985.         loop    top_carry_loop_16
  986.  
  987. no_more_carry_16:
  988.         add     n2p, 2                  ; increase by word size
  989.         add     si, 2
  990.         dec     carry_steps             ; use one less step
  991.         dec     j
  992.         ja      top_inner_loop_16
  993.  
  994.         add     n1p, 2                  ; increase by word size
  995.         add     di, 2
  996.         mov     si, di                  ; start with si=di
  997.  
  998.         dec     doublesteps             ; reduce the carry steps needed
  999.         mov     ax, doublesteps
  1000.         mov     carry_steps, ax
  1001.  
  1002.  
  1003.         dec     i
  1004.         ja      top_outer_loop_16
  1005.  
  1006.         ; result is now r, a double wide bignumber
  1007.         jmp     bottom
  1008.  
  1009.  
  1010. use_32_bit:
  1011. .386
  1012.         mov     ax, word ptr n1         ; load pointers
  1013.         mov     n1p, ax
  1014.  
  1015.         mov     dx, bnlength            ; set outer loop counter
  1016.         shr     dx, 2                   ; byte = 1/4 dword
  1017.         mov     steps, dx               ; save in steps
  1018.         mov     i, dx
  1019.         shl     dx, 1                   ; double steps
  1020.  
  1021.         sub     eax, eax                ; clear eax
  1022.         mov     cx, dx                  ; size of doublebignumber in dwords
  1023.         mov     di, word ptr r          ; es already set
  1024.         rep     stosd                   ; initialize r to 0
  1025.  
  1026.         sub     dx, 2                   ; only 2*s-2 steps are really needed
  1027.         mov     doublesteps, dx
  1028.         mov     carry_steps, dx
  1029.         mov     di, word ptr r
  1030.         mov     si, di                  ; both si and di are used here
  1031.  
  1032. top_outer_loop_32:
  1033.         mov     ax, word ptr n2         ; set n2p pointer
  1034.         mov     n2p, ax
  1035.         mov     ax, steps               ; set inner loop counter
  1036.         mov     j, ax
  1037.  
  1038. top_inner_loop_32:
  1039.         mov     bx, n1p
  1040.         mov     eax, es:[bx]
  1041.         mov     bx, n2p
  1042.         mul     dword ptr es:[bx]
  1043.  
  1044.         mov     bx, si
  1045.         add     es:[bx], eax            ; add low dword
  1046.         lahf                            ; save carry flag
  1047.         add     bx, 4                   ; increase by size of dword
  1048.         sahf                            ; restor carry flag
  1049.         adc     es:[bx], edx            ; add high dword
  1050.         jnc     no_more_carry_32        ; carry loop not necessary
  1051.  
  1052.         mov     cx, carry_steps         ; how many till end of double big number
  1053.         jcxz    no_more_carry_32
  1054.         add     bx, 4                   ; move pointer to next dword
  1055.  
  1056.         ; loop until no more carry or until end of double big number
  1057. top_carry_loop_32:
  1058.         add     dword ptr es:[bx], 1    ; use add, not inc
  1059.         jnc     no_more_carry_32
  1060.         add     bx, 4                   ; increase by size of dword
  1061.         loop    top_carry_loop_32
  1062.  
  1063. no_more_carry_32:
  1064.         add     n2p, 4                  ; increase by dword size
  1065.         add     si, 4
  1066.         dec     carry_steps             ; use one less step
  1067.         dec     j
  1068.         ja      top_inner_loop_32
  1069.  
  1070.         add     n1p, 4                  ; increase by dword size
  1071.         add     di, 4
  1072.         mov     si, di                  ; start with si=di
  1073.  
  1074.         dec     doublesteps             ; reduce the carry steps needed
  1075.         mov     ax, doublesteps
  1076.         mov     carry_steps, ax
  1077.  
  1078.  
  1079.         dec     i
  1080.         ja      top_outer_loop_32
  1081.  
  1082.         ; result is now r, a double wide bignumber
  1083.  
  1084. bottom:
  1085. .8086
  1086.  
  1087.         cmp     samevar, 1              ; were the variable the same ones?
  1088.         je      pos_answer              ; if yes, then jump
  1089.  
  1090.         mov     al, sign1               ; is result + or - ?
  1091.         cmp     al, sign2               ; sign(n1) == sign(n2) ?
  1092.         je      pos_answer              ; yes
  1093.         push    bnlength                ; save bnlength
  1094.         shl     bnlength, 1             ; temporarily double bnlength
  1095.                                         ; for double wide bignumber
  1096.         invoke  neg_a_bn, r             ; does not affect ES
  1097.         pop     bnlength                ; restore bnlength
  1098. pos_answer:
  1099.  
  1100.         mov     dx, es                  ; return r in dx:ax
  1101.         mov     ax, word ptr r
  1102.         ret
  1103. unsafe_full_mult_bn   ENDP
  1104.  
  1105. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1106. ; r = n1 * n2 calculating only the top rlength bytes
  1107. ; Note: r will be of length rlength
  1108. ;       2*bnlength <= rlength < bnlength
  1109. ;       n1 and n2 can be the same pointer
  1110. ; SIDE-EFFECTS: n1 and n2 are changed to their absolute values
  1111. ;
  1112. unsafe_mult_bn   PROC USES di si, r:bn_t, n1:bn_t, n2:bn_t
  1113. LOCAL sign1:byte, sign2:byte, samevar:byte, \
  1114.       i:word, j:word, steps:word, doublesteps:word, \
  1115.       carry_steps:word, skips:word, \
  1116.       n1p: ptr byte, n2p: ptr byte
  1117.  
  1118. ; By forcing the bignumber to be positive and keeping track of the sign
  1119. ; bits separately, quite a few multiplies are saved.
  1120.  
  1121.         ; set the ES register here
  1122.         les     bx, n1                      ; check for sign bits
  1123.         add     bx, bnlength
  1124.         dec     bx
  1125.         mov     al, es:[bx]
  1126.         and     al, 80h                     ; check the sign bit
  1127.         mov     sign1, al
  1128.         jz      already_pos1
  1129.         invoke  neg_a_bn, n1
  1130. already_pos1:
  1131.  
  1132. ; Test to see if n1 and n2 are the same variable.  It would be better to
  1133. ; use square_bn(), but it could happen.
  1134.  
  1135.         mov     samevar, 1                  ; assume they are the same
  1136.         mov     bx, word ptr n2
  1137.         cmp     bx, word ptr n1             ; are they the same?
  1138.         je      already_pos2                ; if so, it has already been negated
  1139.         mov     samevar, 0                  ; they weren't the same after all
  1140.  
  1141.         add     bx, bnlength
  1142.         dec     bx
  1143.         mov     al, es:[bx]
  1144.         and     al, 80h                     ; check the sign bit
  1145.         mov     sign2, al
  1146.         jz      already_pos2
  1147.         invoke  neg_a_bn, n2
  1148. already_pos2:
  1149.  
  1150.         mov     ax, word ptr n1         ; load pointers
  1151.         mov     n1p, ax
  1152.  
  1153.         mov     ax, bnlength
  1154.         shl     ax, 1                   ; 2*bnlength
  1155.         sub     ax, rlength             ; 2*bnlength-rlength
  1156.         add     word ptr n2, ax         ; n2 = n2+2*bnlength-rlength
  1157.  
  1158. ; in the following loops, the following pointers are used
  1159. ;   n1p, n2p = points to the part of n1, n2 being used
  1160. ;   di = points to part of doublebignumber used in outer loop
  1161. ;   si = points to part of doublebignumber used in inner loop
  1162. ;   bx = points to part of doublebignumber for carry flag loop
  1163.  
  1164.         cmp     cpu, 386                ; check cpu
  1165.         je      use_32_bit              ; use faster 32 bit code if possible
  1166.  
  1167.         sub     ax, ax                  ; clear ax
  1168.         mov     cx, rlength             ; size of r in bytes
  1169.         shr     cx, 1                   ; byte = 1/2 word
  1170.         mov     di, word ptr r          ; es already set
  1171.         rep     stosw                   ; initialize r to 0
  1172.  
  1173.         mov     ax, rlength             ; set steps for first loop
  1174.         sub     ax, bnlength
  1175.         shr     ax, 1                   ; byte = 1/2 word
  1176.         mov     steps, ax               ; save in steps
  1177.  
  1178.         mov     ax, bnlength
  1179.         shr     ax, 1                   ; byte = 1/2 word
  1180.         mov     i, ax
  1181.  
  1182.         sub     ax, steps
  1183.         mov     skips, ax               ; how long to skip over pointer shifts
  1184.  
  1185.         mov     ax, rlength             ; set steps for first loop
  1186.         shr     ax, 1                   ; byte = 1/2 word
  1187.         sub     ax, 2                   ; only rlength/2-2 steps are really needed
  1188.         mov     doublesteps, ax
  1189.         mov     carry_steps, ax
  1190.  
  1191.         mov     di, word ptr r          ; this is r
  1192.         mov     si, di                  ; both si and di are used here
  1193.  
  1194. top_outer_loop_16:
  1195.         mov     ax, word ptr n2         ; set n2p pointer
  1196.         mov     n2p, ax
  1197.         mov     ax, steps               ; set inner loop counter
  1198.         mov     j, ax
  1199.  
  1200. top_inner_loop_16:
  1201.         mov     bx, n1p
  1202.         mov     ax, es:[bx]
  1203.         mov     bx, n2p
  1204.         mul     word ptr es:[bx]
  1205.  
  1206.         mov     bx, si
  1207.         add     es:[bx], ax             ; add low word
  1208.         inc     bx                      ; increase by size of word
  1209.         inc     bx
  1210.         adc     es:[bx], dx             ; add high word
  1211.         jnc     no_more_carry_16        ; carry loop not necessary
  1212.  
  1213.         mov     cx, carry_steps         ; how many till end of double big number
  1214.         jcxz    no_more_carry_16
  1215.         add     bx, 2                   ; move pointer to next word
  1216.  
  1217.         ; loop until no more carry or until end of double big number
  1218. top_carry_loop_16:
  1219.         add     word ptr es:[bx], 1     ; use add, not inc
  1220.         jnc     no_more_carry_16
  1221.         add     bx, 2                   ; increase by size of word
  1222.         loop    top_carry_loop_16
  1223.  
  1224. no_more_carry_16:
  1225.         add     n2p, 2                  ; increase by word size
  1226.         add     si, 2
  1227.         dec     carry_steps             ; use one less step
  1228.         dec     j
  1229.         ja      top_inner_loop_16
  1230.  
  1231.         add     n1p, 2                  ; increase by word size
  1232.  
  1233.         cmp     skips, 0
  1234.         je      type2_shifts_16
  1235.         sub     word ptr n2, 2          ; shift n2 back a word
  1236.         inc     steps                   ; one more step this time
  1237.         ; leave di and doublesteps where they are
  1238.         dec     skips                   ; keep track of how many times we've done this
  1239.         jmp     shifts_bottom_16
  1240. type2_shifts_16:
  1241.         add     di, 2                   ; shift di forward a word
  1242.         dec     doublesteps             ; reduce the carry steps needed
  1243. shifts_bottom_16:
  1244.         mov     si, di                  ; start with si=di
  1245.         mov     ax, doublesteps
  1246.         mov     carry_steps, ax
  1247.  
  1248.         dec     i
  1249.         ja      top_outer_loop_16
  1250.  
  1251.         ; result is in r
  1252.         jmp     bottom
  1253.  
  1254.  
  1255. use_32_bit:
  1256. .386
  1257.  
  1258.         sub     eax, eax                ; clear eax
  1259.         mov     cx, rlength             ; size of r in bytes
  1260.         shr     cx, 2                   ; byte = 1/4 dword
  1261.         mov     di, word ptr r          ; es already set
  1262.         rep     stosd                   ; initialize r to 0
  1263.  
  1264.         mov     ax, rlength             ; set steps for first loop
  1265.         sub     ax, bnlength
  1266.         shr     ax, 2                   ; byte = 1/4 dword
  1267.         mov     steps, ax               ; save in steps
  1268.  
  1269.         mov     ax, bnlength
  1270.         shr     ax, 2                   ; byte = 1/4 dword
  1271.         mov     i, ax
  1272.  
  1273.         sub     ax, steps
  1274.         mov     skips, ax               ; how long to skip over pointer shifts
  1275.  
  1276.         mov     ax, rlength             ; set steps for first loop
  1277.         shr     ax, 2                   ; byte = 1/4 dword
  1278.         sub     ax, 2                   ; only rlength/4-2 steps are really needed
  1279.         mov     doublesteps, ax
  1280.         mov     carry_steps, ax
  1281.  
  1282.         mov     di, word ptr r          ; this is r
  1283.         mov     si, di                  ; both si and di are used here
  1284.  
  1285.  
  1286. top_outer_loop_32:
  1287.         mov     ax, word ptr n2         ; set n2p pointer
  1288.         mov     n2p, ax
  1289.         mov     ax, steps               ; set inner loop counter
  1290.         mov     j, ax
  1291.  
  1292. top_inner_loop_32:
  1293.         mov     bx, n1p
  1294.         mov     eax, es:[bx]
  1295.         mov     bx, n2p
  1296.         mul     dword ptr es:[bx]
  1297.  
  1298.         mov     bx, si
  1299.         add     es:[bx], eax            ; add low dword
  1300.         lahf                            ; save carry flag
  1301.         add     bx, 4                   ; increase by size of dword
  1302.         sahf                            ; restor carry flag
  1303.         adc     es:[bx], edx            ; add high dword
  1304.         jnc     no_more_carry_32        ; carry loop not necessary
  1305.  
  1306.         mov     cx, carry_steps         ; how many till end of double big number
  1307.         jcxz    no_more_carry_32
  1308.         add     bx, 4                   ; move pointer to next dword
  1309.  
  1310.         ; loop until no more carry or until end of r
  1311. top_carry_loop_32:
  1312.         add     dword ptr es:[bx], 1    ; use add, not inc
  1313.         jnc     no_more_carry_32
  1314.         add     bx, 4                   ; increase by size of dword
  1315.         loop    top_carry_loop_32
  1316.  
  1317. no_more_carry_32:
  1318.         add     n2p, 4                  ; increase by dword size
  1319.         add     si, 4
  1320.         dec     carry_steps             ; use one less step
  1321.         dec     j
  1322.         ja      top_inner_loop_32
  1323.  
  1324.         add     n1p, 4                  ; increase by dword size
  1325.  
  1326.         cmp     skips, 0
  1327.         je      type2_shifts_32
  1328.         sub     word ptr n2, 4          ; shift n2 back a dword
  1329.         inc     steps                   ; one more step this time
  1330.         ; leave di and doublesteps where they are
  1331.         dec     skips                   ; keep track of how many times we've done this
  1332.         jmp     shifts_bottom_32
  1333. type2_shifts_32:
  1334.         add     di, 4                   ; shift di forward a dword
  1335.         dec     doublesteps             ; reduce the carry steps needed
  1336. shifts_bottom_32:
  1337.         mov     si, di                  ; start with si=di
  1338.         mov     ax, doublesteps
  1339.         mov     carry_steps, ax
  1340.  
  1341.         dec     i
  1342.         ja      top_outer_loop_32
  1343.  
  1344.         ; result is in r
  1345.  
  1346. bottom:
  1347. .8086
  1348.         cmp     samevar, 1              ; were the variable the same ones?
  1349.         je      pos_answer              ; if yes, then jump
  1350.  
  1351.         mov     al, sign1               ; is result + or - ?
  1352.         cmp     al, sign2               ; sign(n1) == sign(n2) ?
  1353.         je      pos_answer              ; yes
  1354.         push    bnlength                ; save bnlength
  1355.         mov     ax, rlength
  1356.         mov     bnlength, ax            ; set bnlength = rlength
  1357.         invoke  neg_a_bn, r             ; does not affect ES
  1358.         pop     bnlength                ; restore bnlength
  1359. pos_answer:
  1360.  
  1361.         mov     dx, es                  ; return r in dx:ax
  1362.         mov     ax, word ptr r
  1363.         ret
  1364. unsafe_mult_bn   ENDP
  1365.  
  1366. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1367. ; r = n^2
  1368. ;   because of the symetry involved, n^2 is much faster than n*n
  1369. ;   for a bignumber of length l
  1370. ;      n*n takes l^2 multiplications
  1371. ;      n^2 takes (l^2+l)/2 multiplications
  1372. ;          which is about 1/2 n*n as l gets large
  1373. ;  uses the fact that (a+b+c+...)^2 = (a^2+b^2+c^2+...)+2(ab+ac+bc+...)
  1374. ;
  1375. ; Note: r will be a double wide result, 2*bnlength
  1376. ; SIDE-EFFECTS: n is changed to its absolute value
  1377. ;
  1378. unsafe_full_square_bn   PROC USES di si, r:bn_t, n:bn_t
  1379. LOCAL i:word, j:word, steps:word, doublesteps:word, carry_steps:word, \
  1380.       rp1: ptr byte, rp2: ptr byte
  1381.  
  1382. ; This routine uses near variables and far pointers together in the
  1383. ; inner-most loops.  Therefore, there is little to gain by setting DS
  1384. ; to the far segment.  Instead, set ES to the far segment and use segment
  1385. ; overrides where necessary.
  1386.  
  1387. ; By forcing the bignumber to be positive and keeping track of the sign
  1388. ; bits separately, quite a few multiplies are saved.
  1389.  
  1390.         ; load ES here
  1391.         les     bx, n                       ; check for sign bit
  1392.         add     bx, bnlength
  1393.         dec     bx
  1394.         mov     al, es:[bx]
  1395.         and     al, 80h                     ; check the sign bit
  1396.         jz      already_pos
  1397.         invoke  neg_a_bn, n
  1398. already_pos:
  1399.  
  1400. ; in the following loops, the following pointers are used
  1401. ;   n1p(di), n2p(si) = points to the parts of n being used
  1402. ;   rp1 = points to part of doublebignumber used in outer loop
  1403. ;   rp2 = points to part of doublebignumber used in inner loop
  1404. ;   bx = points to part of doublebignumber for carry flag loop
  1405.  
  1406.         mov     cx, bnlength            ; size of doublebignumber in words
  1407.  
  1408.         cmp     cpu, 386                ; check cpu
  1409.         je      use_32_bit              ; use faster 32 bit code if possible
  1410.  
  1411.         sub     ax, ax                  ; clear ax
  1412.         ; 2{twice the size}*bnlength/2{bytes per word}
  1413.         mov     di, word ptr r          ; es already set
  1414.         rep     stosw                   ; initialize r to 0
  1415.  
  1416.         mov     dx, bnlength            ; set outer loop counter
  1417.         shr     dx, 1                   ; byte = 1/2 word
  1418.         dec     dx                      ; don't need to do last one
  1419.         mov     i, dx                   ; loop counter
  1420.         mov     steps, dx               ; save in steps
  1421.         shl     dx, 1                   ; double steps
  1422.         sub     dx, 1                   ; only 2*s-1 steps are really needed
  1423.         mov     doublesteps, dx
  1424.         mov     carry_steps, dx
  1425.         mov     ax, word ptr r
  1426.         add     ax, 2                   ; start with second word
  1427.         mov     rp1, ax
  1428.         mov     rp2, ax                 ; start with rp2=rp1
  1429.         mov     di, word ptr n          ; load n1p pointer
  1430.  
  1431.         cmp     i, 0                    ; if bignumberlength is 2
  1432.         je      skip_middle_terms_16
  1433.  
  1434. top_outer_loop_16:
  1435.         mov     si, di                  ; set n2p pointer
  1436.         add     si, 2                   ; to 1 word beyond n1p(di)
  1437.         mov     ax, steps               ; set inner loop counter
  1438.         mov     j, ax
  1439.  
  1440. top_inner_loop_16:
  1441.         mov     ax, es:[di]
  1442.         mul     word ptr es:[si]
  1443.  
  1444.         mov     bx, rp2
  1445.         add     es:[bx], ax             ; add low word
  1446.         inc     bx                      ; increase by size of word
  1447.         inc     bx
  1448.         adc     es:[bx], dx             ; add high word
  1449.         jnc     no_more_carry_16        ; carry loop not necessary
  1450.  
  1451.         mov     cx, carry_steps         ; how many till end of double big number
  1452.         jcxz    no_more_carry_16
  1453.         add     bx, 2                   ; move pointer to next word
  1454.  
  1455.         ; loop until no more carry or until end of double big number
  1456. top_carry_loop_16:
  1457.         add     word ptr es:[bx], 1     ; use add, not inc
  1458.         jnc     no_more_carry_16
  1459.         add     bx, 2                   ; increase by size of word
  1460.         loop    top_carry_loop_16
  1461.  
  1462. no_more_carry_16:
  1463.         add     si, 2                   ; increase by word size
  1464.         add     rp2, 2
  1465.         dec     carry_steps             ; use one less step
  1466.         dec     j
  1467.         ja      top_inner_loop_16
  1468.  
  1469.         add     di, 2                   ; increase by word size
  1470.         add     rp1, 4                  ; increase by 2*word size
  1471.         mov     ax, rp1
  1472.         mov     rp2, ax                 ; start with rp2=rp1
  1473.  
  1474.         sub     doublesteps,2           ; reduce the carry steps needed
  1475.         mov     ax, doublesteps
  1476.         mov     carry_steps, ax
  1477.  
  1478.         dec     steps                   ; use one less step
  1479.         dec     i
  1480.         ja      top_outer_loop_16
  1481.  
  1482.         ; All the middle terms have been multiplied.  Now double it.
  1483.         push    bnlength
  1484.         shl     bnlength, 1             ; r is a double wide bignumber
  1485.         invoke  double_a_bn, r
  1486.         pop     bnlength
  1487.  
  1488. skip_middle_terms_16:
  1489. ; Now go back and add in the squared terms.
  1490. ; In the following loops, the following pointers are used
  1491. ;   n1p(di) = points to the parts of n being used
  1492. ;   rp1(si) = points to part of doublebignumber used in outer loop
  1493. ;   bx = points to part of doublebignumber for carry flag loop
  1494.  
  1495.         mov     di, word ptr n          ; load n1p pointer
  1496.  
  1497.         mov     dx, bnlength            ; set outer loop counter
  1498.         shr     dx, 1                   ; 1 bytes = 1/2 word
  1499.         mov     i, dx                   ; loop counter
  1500.         shl     dx, 1                   ; double steps
  1501.  
  1502.         sub     dx, 2                   ; only 2*s-2 steps are really needed
  1503.         mov     doublesteps, dx
  1504.         mov     carry_steps, dx
  1505.         mov     si, word ptr r          ; set rp1
  1506.  
  1507. top_outer_loop_squares_16:
  1508.  
  1509.         mov     ax, es:[di]
  1510.         mul     ax                      ; square it
  1511.  
  1512.         mov     bx, si
  1513.         add     es:[bx], ax             ; add low word
  1514.         inc     bx                      ; increase by size of word
  1515.         inc     bx
  1516.         adc     es:[bx], dx             ; add high word
  1517.         jnc     no_more_carry_squares_16 ; carry loop not necessary
  1518.  
  1519.         mov     cx, carry_steps         ; how many till end of double big number
  1520.         jcxz    no_more_carry_squares_16
  1521.         add     bx, 2                   ; move pointer to next word
  1522.  
  1523.         ; loop until no more carry or until end of double big number
  1524. top_carry_loop_squares_16:
  1525.         add     word ptr es:[bx], 1     ; use add, not inc
  1526.         jnc     no_more_carry_squares_16
  1527.         add     bx, 2                   ; increase by size of word
  1528.         loop    top_carry_loop_squares_16
  1529.  
  1530. no_more_carry_squares_16:
  1531.         add     di, 2                   ; increase by word size
  1532.         add     si, 4                   ; increase by 2*word size
  1533.  
  1534.         sub     doublesteps,2           ; reduce the carry steps needed
  1535.         mov     ax, doublesteps
  1536.         mov     carry_steps, ax
  1537.  
  1538.         dec     i
  1539.         ja      top_outer_loop_squares_16
  1540.  
  1541.  
  1542.         ; result is in r, a double wide bignumber
  1543.         jmp     bottom
  1544.  
  1545.  
  1546. use_32_bit:
  1547. .386
  1548.  
  1549.         sub     eax, eax                ; clear eax
  1550.         ; 2{twice the size}*bnlength/4{bytes per word}
  1551.         shr     cx, 1                   ; size of doublebignumber in dwords
  1552.         mov     di, word ptr r          ; es already set
  1553.         rep     stosd                   ; initialize r to 0
  1554.  
  1555.         mov     dx, bnlength            ; set outer loop counter
  1556.         shr     dx, 2                   ; byte = 1/4 dword
  1557.         dec     dx                      ; don't need to do last one
  1558.         mov     i, dx                   ; loop counter
  1559.         mov     steps, dx               ; save in steps
  1560.         shl     dx, 1                   ; double steps
  1561.  
  1562.         sub     dx, 1                   ; only 2*s-1 steps are really needed
  1563.         mov     doublesteps, dx
  1564.         mov     carry_steps, dx
  1565.         mov     ax, word ptr r
  1566.         add     ax, 4                   ; start with second dword
  1567.         mov     rp1, ax
  1568.         mov     rp2, ax                 ; start with rp2=rp1
  1569.         mov     di, word ptr n          ; load n1p pointer
  1570.  
  1571.         cmp     i, 0                    ; if bignumberlength is 4
  1572.         je      skip_middle_terms_32
  1573.  
  1574. top_outer_loop_32:
  1575.         mov     si, di                  ; set n2p pointer
  1576.         add     si, 4                   ; to 1 dword beyond n1p(di)
  1577.         mov     ax, steps               ; set inner loop counter
  1578.         mov     j, ax
  1579.  
  1580. top_inner_loop_32:
  1581.         mov     eax, es:[di]
  1582.         mul     dword ptr es:[si]
  1583.  
  1584.         mov     bx, rp2
  1585.         add     es:[bx], eax            ; add low dword
  1586.         lahf
  1587.         add     bx, 4                   ; increase by size of dword
  1588.         sahf
  1589.         adc     es:[bx], edx            ; add high dword
  1590.         jnc     no_more_carry_32        ; carry loop not necessary
  1591.  
  1592.         mov     cx, carry_steps         ; how many till end of double big number
  1593.         jcxz    no_more_carry_32
  1594.         add     bx, 4                   ; move pointer to next dword
  1595.  
  1596.         ; loop until no more carry or until end of double big number
  1597. top_carry_loop_32:
  1598.         add     dword ptr es:[bx], 1    ; use add, not inc
  1599.         jnc     no_more_carry_32
  1600.         add     bx, 4                   ; increase by size of dword
  1601.         loop    top_carry_loop_32
  1602.  
  1603. no_more_carry_32:
  1604.         add     si, 4                   ; increase by dword size
  1605.         add     rp2, 4
  1606.         dec     carry_steps             ; use one less step
  1607.         dec     j
  1608.         ja      top_inner_loop_32
  1609.  
  1610.         add     di, 4                   ; increase by dword size
  1611.         add     rp1, 8                  ; increase by 2*dword size
  1612.         mov     ax, rp1
  1613.         mov     rp2, ax                 ; start with rp2=rp1
  1614.  
  1615.         sub     doublesteps,2           ; reduce the carry steps needed
  1616.         mov     ax, doublesteps
  1617.         mov     carry_steps, ax
  1618.  
  1619.         dec     steps                   ; use one less step
  1620.         dec     i
  1621.         ja      top_outer_loop_32
  1622.  
  1623.         ; All the middle terms have been multiplied.  Now double it.
  1624.         push    bnlength
  1625.         shl     bnlength, 1             ; r is a double wide bignumber
  1626.         invoke  double_a_bn, r
  1627.         pop     bnlength
  1628.  
  1629. skip_middle_terms_32:
  1630.  
  1631. ; Now go back and add in the squared terms.
  1632. ; In the following loops, the following pointers are used
  1633. ;   n1p(di) = points to the parts of n being used
  1634. ;   rp1(si) = points to part of doublebignumber used in outer loop
  1635. ;   bx = points to part of doublebignumber for carry flag loop
  1636.  
  1637.         mov     di, word ptr n          ; load n1p pointer
  1638.  
  1639.         mov     dx, bnlength            ; set outer loop counter
  1640.         shr     dx, 2                   ; 1 bytes = 1/4 dword
  1641.         mov     i, dx                   ; loop counter
  1642.         shl     dx, 1                   ; double steps
  1643.  
  1644.         sub     dx, 2                   ; only 2*s-2 steps are really needed
  1645.         mov     doublesteps, dx
  1646.         mov     carry_steps, dx
  1647.         mov     si, word ptr r          ; set rp1
  1648.  
  1649. top_outer_loop_squares_32:
  1650.  
  1651.         mov     eax, es:[di]
  1652.         mul     eax                     ; square it
  1653.  
  1654.         mov     bx, si
  1655.         add     es:[bx], eax            ; add low dword
  1656.         lahf
  1657.         add     bx, 4                   ; increase by size of dword
  1658.         sahf
  1659.         adc     es:[bx], edx            ; add high dword
  1660.         jnc     no_more_carry_squares_32 ; carry loop not necessary
  1661.  
  1662.         mov     cx, carry_steps         ; how many till end of double big number
  1663.         jcxz    no_more_carry_squares_32
  1664.         add     bx, 4                   ; move pointer to next dword
  1665.  
  1666.         ; loop until no more carry or until end of double big number
  1667. top_carry_loop_squares_32:
  1668.         add     dword ptr es:[bx], 1    ; use add, not inc
  1669.         jnc     no_more_carry_squares_32
  1670.         add     bx, 4                   ; increase by size of dword
  1671.         loop    top_carry_loop_squares_32
  1672.  
  1673. no_more_carry_squares_32:
  1674.         add     di, 4                   ; increase by dword size
  1675.         add     si, 8                   ; increase by 2*dword size
  1676.  
  1677.         sub     doublesteps,2           ; reduce the carry steps needed
  1678.         mov     ax, doublesteps
  1679.         mov     carry_steps, ax
  1680.  
  1681.         dec     i
  1682.         ja      top_outer_loop_squares_32
  1683.  
  1684.  
  1685.         ; result is in r, a double wide bignumber
  1686.  
  1687. bottom:
  1688. .8086
  1689.  
  1690. ; since it is a square, the result has to already be positive
  1691.  
  1692.         mov     dx, es                  ; return r in dx:ax
  1693.         mov     ax, word ptr r
  1694.         ret
  1695. unsafe_full_square_bn   ENDP
  1696.  
  1697. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  1698. ; r = n^2
  1699. ;   because of the symetry involved, n^2 is much faster than n*n
  1700. ;   for a bignumber of length l
  1701. ;      n*n takes l^2 multiplications
  1702. ;      n^2 takes (l^2+l)/2 multiplications
  1703. ;          which is about 1/2 n*n as l gets large
  1704. ;  uses the fact that (a+b+c+...)^2 = (a^2+b^2+c^2+...)+2(ab+ac+bc+...)
  1705. ;
  1706. ; Note: r will be of length rlength
  1707. ;       2*bnlength >= rlength > bnlength
  1708. ; SIDE-EFFECTS: n is changed to its absolute value
  1709. ;
  1710. unsafe_square_bn   PROC USES di si, r:bn_t, n:bn_t
  1711. LOCAL i:word, j:word, steps:word, doublesteps:word, carry_steps:word, \
  1712.       skips:word, rodd:word, \
  1713.       n3p: ptr byte, \
  1714.       rp1: ptr byte, rp2: ptr byte
  1715.  
  1716. ; This whole procedure would be a great deal simpler if we could assume that
  1717. ; rlength < 2*bnlength (that is, not =).  Therefore, we will take the
  1718. ; easy way out and call full_square_bn() if it is.
  1719.         mov     ax, rlength
  1720.         shr     ax, 1                   ; 1/2 * rlength
  1721.         cmp     ax, bnlength            ; 1/2 * rlength == bnlength?
  1722.         jne     not_full_square
  1723. ifndef ??version
  1724.         invoke  unsafe_full_square_bn, r, n
  1725. else
  1726.         invoke2 unsafe_full_square_bn, r, n
  1727. endif
  1728.         ; dx:ax is still loaded with return value
  1729.         jmp     quit_proc               ; we're outa here
  1730. not_full_square:
  1731.  
  1732. ; This routine uses near variables and far pointers together in the
  1733. ; inner-most loops.  Therefore, there is little to gain by setting DS
  1734. ; to the far segment.  Instead, set ES to the far segment and use segment
  1735. ; overrides where necessary.
  1736.  
  1737. ; By forcing the bignumber to be positive and keeping track of the sign
  1738. ; bits separately, quite a few multiplies are saved.
  1739.  
  1740.         ; set ES here
  1741.         les     bx, n                       ; check for sign bit
  1742.         add     bx, bnlength
  1743.         dec     bx
  1744.         mov     al, es:[bx]
  1745.         and     al, 80h                     ; check the sign bit
  1746.         jz      already_pos
  1747.         invoke  neg_a_bn, n
  1748. already_pos:
  1749.  
  1750. ; in the following loops, the following pointers are used
  1751. ;   n1p(di), n2p(si) = points to the parts of n being used
  1752. ;   rp1 = points to part of doublebignumber used in outer loop
  1753. ;   rp2 = points to part of doublebignumber used in inner loop
  1754. ;   bx = points to part of doublebignumber for carry flag loop
  1755.  
  1756.         cmp     cpu, 386                ; check cpu
  1757.         je      use_32_bit              ; use faster 32 bit code if possible
  1758.  
  1759.         sub     ax, ax                  ; clear ax
  1760.         mov     cx, rlength             ; size of rlength in bytes
  1761.         shr     cx, 1                   ; byte = 1/2 word
  1762.         mov     di, word ptr r          ; es already set
  1763.         rep     stosw                   ; initialize r to 0
  1764.  
  1765.         ; determine whether r is on an odd or even word in the number
  1766.         ; (even if rlength==2*bnlength, dec r alternates odd/even)
  1767.         mov     ax, bnlength
  1768.         shl     ax, 1                   ; double wide width
  1769.         sub     ax, rlength             ; 2*bnlength-rlength
  1770.         shr     ax, 1                   ; 1 byte = 1/2 word
  1771.         and     ax, 0001h               ; check the odd sign bit
  1772.         mov     rodd, ax
  1773.  
  1774.         mov     ax, bnlength            ; set outer loop counter
  1775.         shr     ax, 1                   ; byte = 1/2 word
  1776.         dec     ax                      ; don't need to do last one
  1777.         mov     i, ax                   ; loop counter
  1778.  
  1779.         mov     ax, rlength             ; set steps for first loop
  1780.         sub     ax, bnlength
  1781.         shr     ax, 1                   ; byte = 1/2 word
  1782.         mov     steps, ax               ; save in steps
  1783.  
  1784.         mov     dx, bnlength
  1785.         shr     dx, 1                   ; bnlength/2
  1786.         add     ax, dx                  ; steps+bnlength/2
  1787.         sub     ax, 2                   ; steps+bnlength/2-2
  1788.         mov     doublesteps, ax
  1789.         mov     carry_steps, ax
  1790.  
  1791.         mov     ax, i
  1792.         sub     ax, steps
  1793.         shr     ax, 1                   ; for both words and dwords
  1794.         mov     skips, ax               ; how long to skip over pointer shifts
  1795.  
  1796.         mov     ax, word ptr r
  1797.         mov     rp1, ax
  1798.         mov     rp2, ax                 ; start with rp2=rp1
  1799.         mov     di, word ptr n          ; load n1p pointer
  1800.         mov     si, di
  1801.         mov     ax, bnlength
  1802.         shr     ax, 1                   ; 1 byte = 1/2 word
  1803.         sub     ax, steps
  1804.         shl     ax, 1                   ; 1 byte = 1/2 word
  1805.         add     si, ax                  ; n2p = n1p + 2*(bnlength/2 - steps)
  1806.         mov     n3p, si                 ; save for later use
  1807.  
  1808.         cmp     i, 0                    ; if bignumberlength is 2
  1809.         je      skip_middle_terms_16
  1810.  
  1811. top_outer_loop_16:
  1812.         mov     ax, steps               ; set inner loop counter
  1813.         mov     j, ax
  1814.  
  1815. top_inner_loop_16:
  1816.         mov     ax, es:[di]
  1817.         mul     word ptr es:[si]
  1818.  
  1819.         mov     bx, rp2
  1820.         add     es:[bx], ax             ; add low word
  1821.         inc     bx                      ; increase by size of word
  1822.         inc     bx
  1823.         adc     es:[bx], dx             ; add high word
  1824.         jnc     no_more_carry_16        ; carry loop not necessary
  1825.  
  1826.         mov     cx, carry_steps         ; how many till end of double big number
  1827.         jcxz    no_more_carry_16
  1828.         add     bx, 2                   ; move pointer to next word
  1829.  
  1830.         ; loop until no more carry or until end of double big number
  1831. top_carry_loop_16:
  1832.         add     word ptr es:[bx], 1     ; use add, not inc
  1833.         jnc     no_more_carry_16
  1834.         add     bx, 2                   ; increase by size of word
  1835.         loop    top_carry_loop_16
  1836.  
  1837. no_more_carry_16:
  1838.         add     si, 2                   ; increase by word size
  1839.         add     rp2, 2
  1840.         dec     carry_steps             ; use one less step
  1841.         dec     j
  1842.         ja      top_inner_loop_16
  1843.  
  1844.         add     di, 2                   ; increase by word size
  1845.  
  1846.         mov     ax, rodd                ; whether r is on an odd or even word
  1847.  
  1848.         cmp     skips, 0
  1849.         jle     type2_shifts_16
  1850.         sub     n3p, 2                  ; point to previous word
  1851.         mov     si, n3p
  1852.         inc     steps                   ; one more step this time
  1853.         ; leave rp1 and doublesteps where they are
  1854.         dec     skips
  1855.         jmp     shifts_bottom_16
  1856. type2_shifts_16:    ; only gets executed once
  1857.         jl      type3_shifts_16
  1858.         sub     steps, ax               ; steps -= (0 or 1)
  1859.         inc     ax                      ; ax = 1 or 2 now
  1860.         sub     doublesteps, ax         ; decrease double steps by 1 or 2
  1861.         shl     ax, 1                   ; 1 byte = 1/2 word
  1862.         add     rp1, ax                 ; add 1 or 2 words
  1863.         mov     si, di
  1864.         add     si, 2                   ; si = di + word
  1865.         dec     skips                   ; make skips negative
  1866.         jmp     shifts_bottom_16
  1867. type3_shifts_16:
  1868.         dec     steps
  1869.         sub     doublesteps, 2
  1870.         add     rp1, 4                  ; + two words
  1871.         mov     si, di
  1872.         add     si, 2                   ; si = di + word
  1873. shifts_bottom_16:
  1874.  
  1875.         mov     ax, rp1
  1876.         mov     rp2, ax                 ; start with rp2=rp1
  1877.  
  1878.         mov     ax, doublesteps
  1879.         mov     carry_steps, ax
  1880.  
  1881.         dec     i
  1882.         ja      top_outer_loop_16
  1883.  
  1884.         ; All the middle terms have been multiplied.  Now double it.
  1885.         push    bnlength                ; save bnlength
  1886.         mov     ax, rlength
  1887.         mov     bnlength, ax            ; r is of length rlength
  1888.         invoke  double_a_bn, r
  1889.         pop     bnlength
  1890.  
  1891. skip_middle_terms_16:
  1892. ; Now go back and add in the squared terms.
  1893. ; In the following loops, the following pointers are used
  1894. ;   n1p(di) = points to the parts of n being used
  1895. ;   rp1(si) = points to part of doublebignumber used in outer loop
  1896. ;   bx = points to part of doublebignumber for carry flag loop
  1897.  
  1898.         ; be careful, the next dozen or so lines are confusing!
  1899.  
  1900.         ; determine whether r is on an odd or even word in the number
  1901.         mov     ax, bnlength
  1902.         shl     ax, 1                   ; double wide width
  1903.         sub     ax, rlength             ; 2*bnlength-rlength
  1904.         mov     dx, ax                  ; save this for a moment
  1905.         and     ax, 0002h               ; check the odd sign bit
  1906.  
  1907.         mov     si, word ptr r
  1908.         add     si, ax                  ; depending on odd or even byte
  1909.  
  1910.         shr     dx, 1                   ; assumes word size
  1911.         inc     dx
  1912.         and     dx, 0FFFEh              ; ~2+1, turn off last bit, mult of 2
  1913.         mov     di, word ptr n
  1914.         add     di, dx
  1915.  
  1916.         mov     ax, bnlength
  1917.         sub     ax, dx
  1918.         shr     ax, 1                   ; 1 byte = 1/2 word
  1919.         mov     i, ax
  1920.  
  1921.         shl     ax, 1                   ; double steps
  1922.         sub     ax, 2                   ; only 2*s-2 steps are really needed
  1923.         mov     doublesteps, ax
  1924.         mov     carry_steps, ax
  1925.  
  1926. top_outer_loop_squares_16:
  1927.  
  1928.         mov     ax, es:[di]
  1929.         mul     ax                      ; square it
  1930.  
  1931.         mov     bx, si
  1932.         add     es:[bx], ax             ; add low word
  1933.         inc     bx                      ; increase by size of word
  1934.         inc     bx
  1935.         adc     es:[bx], dx             ; add high word
  1936.         jnc     no_more_carry_squares_16 ; carry loop not necessary
  1937.  
  1938.         mov     cx, carry_steps         ; how many till end of double big number
  1939.         jcxz    no_more_carry_squares_16
  1940.         add     bx, 2                   ; move pointer to next word
  1941.  
  1942.         ; loop until no more carry or until end of double big number
  1943. top_carry_loop_squares_16:
  1944.         add     word ptr es:[bx], 1     ; use add, not inc
  1945.         jnc     no_more_carry_squares_16
  1946.         add     bx, 2                   ; increase by size of word
  1947.         loop    top_carry_loop_squares_16
  1948.  
  1949. no_more_carry_squares_16:
  1950.         add     di, 2                   ; increase by word size
  1951.         add     si, 4                   ; increase by 2*word size
  1952.  
  1953.         sub     doublesteps,2           ; reduce the carry steps needed
  1954.         mov     ax, doublesteps
  1955.         mov     carry_steps, ax
  1956.  
  1957.         dec     i
  1958.         ja      top_outer_loop_squares_16
  1959.  
  1960.  
  1961.         ; result is in r
  1962.         jmp     bottom
  1963.  
  1964.  
  1965. use_32_bit:
  1966. .386
  1967.         sub     eax, eax                ; clear eax
  1968.         mov     cx, rlength             ; size of rlength in bytes
  1969.         shr     cx, 2                   ; byte = 1/4 dword
  1970.         mov     di, word ptr r          ; es already set
  1971.         rep     stosd                   ; initialize r to 0
  1972.  
  1973.         ; determine whether r is on an odd or even dword in the number
  1974.         ; (even if rlength==2*bnlength, dec r alternates odd/even)
  1975.         mov     ax, bnlength
  1976.         shl     ax, 1                   ; double wide width
  1977.         sub     ax, rlength             ; 2*bnlength-rlength
  1978.         shr     ax, 2                   ; 1 byte = 1/4 dword
  1979.         and     ax, 0001h               ; check the odd sign bit
  1980.         mov     rodd, ax
  1981.  
  1982.         mov     ax, bnlength            ; set outer loop counter
  1983.         shr     ax, 2                   ; byte = 1/4 dword
  1984.         dec     ax                      ; don't need to do last one
  1985.         mov     i, ax                   ; loop counter
  1986.  
  1987.         mov     ax, rlength             ; set steps for first loop
  1988.         sub     ax, bnlength
  1989.         shr     ax, 2                   ; byte = 1/4 dword
  1990.         mov     steps, ax               ; save in steps
  1991.  
  1992.         mov     dx, bnlength
  1993.         shr     dx, 2                   ; bnlength/4
  1994.         add     ax, dx                  ; steps+bnlength/4
  1995.         sub     ax, 2                   ; steps+bnlength/4-2
  1996.         mov     doublesteps, ax
  1997.         mov     carry_steps, ax
  1998.  
  1999.         mov     ax, i
  2000.         sub     ax, steps
  2001.         shr     ax, 1                   ; for both words and dwords
  2002.         mov     skips, ax               ; how long to skip over pointer shifts
  2003.  
  2004.         mov     ax, word ptr r
  2005.         mov     rp1, ax
  2006.         mov     rp2, ax                 ; start with rp2=rp1
  2007.         mov     di, word ptr n          ; load n1p pointer
  2008.         mov     si, di
  2009.         mov     ax, bnlength
  2010.         shr     ax, 2                   ; 1 byte = 1/4 dword
  2011.         sub     ax, steps
  2012.         shl     ax, 2                   ; 1 byte = 1/4 dword
  2013.         add     si, ax                  ; n2p = n1p + bnlength/4 - steps
  2014.         mov     n3p, si                 ; save for later use
  2015.  
  2016.         cmp     i, 0                    ; if bignumberlength is 2
  2017.         je      skip_middle_terms_32
  2018.  
  2019. top_outer_loop_32:
  2020.         mov     ax, steps               ; set inner loop counter
  2021.         mov     j, ax
  2022.  
  2023. top_inner_loop_32:
  2024.         mov     eax, es:[di]
  2025.         mul     dword ptr es:[si]
  2026.  
  2027.         mov     bx, rp2
  2028.         add     es:[bx], eax            ; add low dword
  2029.         lahf                            ; save carry flag
  2030.         add     bx, 4                   ; increase by size of dword
  2031.         sahf                            ; restore carry flag
  2032.         adc     es:[bx], edx            ; add high dword
  2033.         jnc     no_more_carry_32        ; carry loop not necessary
  2034.  
  2035.         mov     cx, carry_steps         ; how many till end of double big number
  2036.         jcxz    no_more_carry_32
  2037.         add     bx, 4                   ; move pointer to next dword
  2038.  
  2039.         ; loop until no more carry or until end of double big number
  2040. top_carry_loop_32:
  2041.         add     dword ptr es:[bx], 1    ; use add, not inc
  2042.         jnc     no_more_carry_32
  2043.         add     bx, 4                   ; increase by size of dword
  2044.         loop    top_carry_loop_32
  2045.  
  2046. no_more_carry_32:
  2047.         add     si, 4                   ; increase by dword size
  2048.         add     rp2, 4
  2049.         dec     carry_steps             ; use one less step
  2050.         dec     j
  2051.         ja      top_inner_loop_32
  2052.  
  2053.         add     di, 4                   ; increase by dword size
  2054.  
  2055.         mov     ax, rodd                ; whether r is on an odd or even dword
  2056.  
  2057.         cmp     skips, 0
  2058.         jle     type2_shifts_32
  2059.         sub     n3p, 4                  ; point to previous dword
  2060.         mov     si, n3p
  2061.         inc     steps                   ; one more step this time
  2062.         ; leave rp1 and doublesteps where they are
  2063.         dec     skips
  2064.         jmp     shifts_bottom_32
  2065. type2_shifts_32:    ; only gets executed once
  2066.         jl      type3_shifts_32
  2067.         sub     steps, ax               ; steps -= (0 or 1)
  2068.         inc     ax                      ; ax = 1 or 2 now
  2069.         sub     doublesteps, ax         ; decrease double steps by 1 or 2
  2070.         shl     ax, 2                   ; 1 byte = 1/4 dword
  2071.         add     rp1, ax                 ; add 1 or 2 dwords
  2072.         mov     si, di
  2073.         add     si, 4                   ; si = di + dword
  2074.         dec     skips                   ; make skips negative
  2075.         jmp     shifts_bottom_32
  2076. type3_shifts_32:
  2077.         dec     steps
  2078.         sub     doublesteps, 2
  2079.         add     rp1, 8                  ; + two dwords
  2080.         mov     si, di
  2081.         add     si, 4                   ; si = di + dword
  2082. shifts_bottom_32:
  2083.  
  2084.         mov     ax, rp1
  2085.         mov     rp2, ax                 ; start with rp2=rp1
  2086.  
  2087.         mov     ax, doublesteps
  2088.         mov     carry_steps, ax
  2089.  
  2090.         dec     i
  2091.         ja      top_outer_loop_32
  2092.  
  2093.         ; All the middle terms have been multiplied.  Now double it.
  2094.         push    bnlength                ; save bnlength
  2095.         mov     ax, rlength
  2096.         mov     bnlength, ax            ; r is of length rlength
  2097.         invoke  double_a_bn, r
  2098.         pop     bnlength
  2099.  
  2100. skip_middle_terms_32:
  2101. ; Now go back and add in the squared terms.
  2102. ; In the following loops, the following pointers are used
  2103. ;   n1p(di) = points to the parts of n being used
  2104. ;   rp1(si) = points to part of doublebignumber used in outer loop
  2105. ;   bx = points to part of doublebignumber for carry flag loop
  2106.  
  2107.         ; be careful, the next dozen or so lines are confusing!
  2108.  
  2109.         ; determine whether r is on an odd or even word in the number
  2110.         mov     ax, bnlength
  2111.         shl     ax, 1                   ; double wide width
  2112.         sub     ax, rlength             ; 2*bnlength-rlength
  2113.         mov     dx, ax                  ; save this for a moment
  2114.         and     ax, 0004h               ; check the odd sign bit
  2115.  
  2116.         mov     si, word ptr r
  2117.         add     si, ax                  ; depending on odd or even byte
  2118.  
  2119.         shr     dx, 2                   ; assumes dword size
  2120.         inc     dx
  2121.         and     dx, 0FFFEh              ; ~2+1, turn off last bit, mult of 2
  2122.         shl     dx, 1
  2123.         mov     di, word ptr n
  2124.         add     di, dx
  2125.  
  2126.         mov     ax, bnlength
  2127.         sub     ax, dx
  2128.         shr     ax, 2                   ; 1 byte = 1/4 dword
  2129.         mov     i, ax
  2130.  
  2131.         shl     ax, 1                   ; double steps
  2132.         sub     ax, 2                   ; only 2*s-2 steps are really needed
  2133.         mov     doublesteps, ax
  2134.         mov     carry_steps, ax
  2135.  
  2136. top_outer_loop_squares_32:
  2137.  
  2138.         mov     eax, es:[di]
  2139.         mul     eax                     ; square it
  2140.  
  2141.         mov     bx, si
  2142.         add     es:[bx], eax            ; add low dword
  2143.         lahf                            ; save carry flag
  2144.         add     bx, 4                   ; increase by size of dword
  2145.         sahf                            ; restore carry flag
  2146.         adc     es:[bx], edx            ; add high dword
  2147.         jnc     no_more_carry_squares_32 ; carry loop not necessary
  2148.  
  2149.         mov     cx, carry_steps         ; how many till end of double big number
  2150.         jcxz    no_more_carry_squares_32
  2151.         add     bx, 4                   ; move pointer to next dword
  2152.  
  2153.         ; loop until no more carry or until end of double big number
  2154. top_carry_loop_squares_32:
  2155.         add     dword ptr es:[bx], 1    ; use add, not inc
  2156.         jnc     no_more_carry_squares_32
  2157.         add     bx, 4                   ; increase by size of dword
  2158.         loop    top_carry_loop_squares_32
  2159.  
  2160. no_more_carry_squares_32:
  2161.         add     di, 4                   ; increase by dword size
  2162.         add     si, 8                   ; increase by 2*dword size
  2163.  
  2164.         sub     doublesteps,2           ; reduce the carry steps needed
  2165.         mov     ax, doublesteps
  2166.         mov     carry_steps, ax
  2167.  
  2168.         dec     i
  2169.         ja      top_outer_loop_squares_32
  2170.  
  2171.  
  2172.         ; result is in r
  2173.  
  2174. bottom:
  2175. .8086
  2176.  
  2177. ; since it is a square, the result has to already be positive
  2178.  
  2179.         mov     dx, es                  ; return r in dx:ax
  2180.         mov     ax, word ptr r
  2181. quit_proc:
  2182.         ret
  2183. unsafe_square_bn   ENDP
  2184. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2185. ; r = n * u  where u is an unsigned integer
  2186. mult_bn_int   PROC USES di si, r:bn_t, n:bn_t, u:word
  2187. LOCAL   lu:dword  ; long unsigned integer in 32 bit math
  2188.  
  2189.         mov     cx, bnlength            ; set outer loop counter
  2190.         mov     ax, ds                  ; mov DS to ES for one segment override
  2191.         mov     es, ax
  2192.         mov     si, word ptr n          ; load pointers ds:si
  2193.         lds     di, r                   ;               ds:di
  2194.  
  2195.         cmp     cpu, 386                ; check cpu
  2196.         je      use_32_bit              ; use faster 32 bit code if possible
  2197.  
  2198.         ; no need to clear r
  2199.         shr     cx, 1                   ; byte = 1/2 word
  2200.         sub     bx, bx                  ; use bx for temp holding carried word
  2201.  
  2202. top_loop_16:
  2203.         mov     ax, [si]                ; load next word from n
  2204.         mul     es:u                    ; n * u
  2205.         add     ax, bx                  ; add last carried upper word
  2206.         adc     dx, 0                   ; inc the carried word if carry flag set
  2207.         mov     bx, dx                  ; save high word in bx
  2208.         mov     [di], ax                ; save low word
  2209.  
  2210.         add     di, 2                   ; next word in r
  2211.         add     si, 2                   ; next word in n
  2212.         loop    top_loop_16
  2213.         jmp     bottom
  2214.  
  2215. use_32_bit:
  2216. .386
  2217.         ; no need to clear r
  2218.  
  2219.         shr     cx, 2                   ; byte = 1/4 dword
  2220.         sub     ebx, ebx                ; use ebx for temp holding carried dword
  2221.  
  2222.         sub     eax, eax                ; clear upper eax
  2223.         mov     ax, es:u                ; convert u (unsigned int)
  2224.         mov     es:lu, eax              ;   to lu (long unsigned int)
  2225.  
  2226. top_loop_32:
  2227.         mov     eax, [si]               ; load next dword from n
  2228.         mul     es:lu                   ; n * lu
  2229.         add     eax, ebx                ; add last carried upper dword
  2230.         adc     edx, 0                  ; inc the carried dword if carry flag set
  2231.         mov     ebx, edx                ; save high dword in ebx
  2232.         mov     [di], eax               ; save low dword
  2233.  
  2234.         add     di, 4                   ; next dword in r
  2235.         add     si, 4                   ; next dword in n
  2236.         loop    top_loop_32
  2237.  
  2238. bottom:
  2239. .8086
  2240.  
  2241.         mov     dx, ds                  ; return r in dx:ax
  2242.         mov     ax, es                  ; restore ds
  2243.         mov     ds, ax
  2244.         mov     ax, word ptr r
  2245.         ret
  2246. mult_bn_int   ENDP
  2247.  
  2248. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2249. ; r *= u  where u is an unsigned integer
  2250. mult_a_bn_int   PROC USES di si, r:bn_t, u:word
  2251.  
  2252.         mov     cx, bnlength            ; set outer loop counter
  2253.         mov     ax, ds                  ; save ds
  2254.         mov     es, ax
  2255.         mov     si, u                   ; save u in    ds:si
  2256.         lds     di, r                   ; load pointer ds:di
  2257.  
  2258.         cmp     cpu, 386                ; check cpu
  2259.         je      use_32_bit              ; use faster 32 bit code if possible
  2260.  
  2261.         ; no need to clear r
  2262.         shr     cx, 1                   ; byte = 1/2 word
  2263.         sub     bx, bx                  ; use bx for temp holding carried word
  2264.  
  2265. top_loop_16:
  2266.         mov     ax, [di]                ; load next word from r
  2267.         mul     si                      ; r * u
  2268.         add     ax, bx                  ; add last carried upper word
  2269.         adc     dx, 0                   ; inc the carried word if carry flag set
  2270.         mov     bx, dx                  ; save high word in bx
  2271.         mov     [di], ax                ; save low word
  2272.  
  2273.         add     di, 2                   ; next word in r
  2274.         loop    top_loop_16
  2275.         jmp     bottom
  2276.  
  2277. use_32_bit:
  2278. .386
  2279.         ; no need to clear r
  2280.         shr     cx, 2                   ; byte = 1/4 dword
  2281.         sub     ebx, ebx                ; use ebx for temp holding carried dword
  2282.         sub     esi, esi                ; clear upper esi
  2283.  
  2284. top_loop_32:
  2285.         mov     eax, [di]               ; load next dword from r
  2286.         mul     esi                     ; r * u
  2287.         add     eax, ebx                ; add last carried upper dword
  2288.         adc     edx, 0                  ; inc the carried dword if carry flag set
  2289.         mov     ebx, edx                ; save high dword in ebx
  2290.         mov     [di], eax               ; save low dword
  2291.  
  2292.         add     di, 4                   ; next dword in r
  2293.         loop    top_loop_32
  2294.  
  2295. bottom:
  2296. .8086
  2297.  
  2298.         mov     dx, ds                  ; return r in dx:ax
  2299.         mov     ax, es                  ; restore ds
  2300.         mov     ds, ax
  2301.         mov     ax, word ptr r
  2302.         ret
  2303. mult_a_bn_int   ENDP
  2304.  
  2305. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2306. ; r = n / u  where u is an unsigned integer
  2307. unsafe_div_bn_int   PROC USES di si, r:bn_t, n:bn_t, u:word
  2308. LOCAL  sign:byte
  2309.  
  2310.         les     bx, n                       ; check for sign bits
  2311.         add     bx, bnlength
  2312.         dec     bx
  2313.         mov     al, es:[bx]
  2314.         and     al, 80h                     ; check the sign bit
  2315.         mov     sign, al
  2316.         jz      already_pos
  2317.         invoke  neg_a_bn, n
  2318. already_pos:
  2319.         mov     cx, bnlength            ; set outer loop counter
  2320.         mov     ax, ds                  ; use es for default ds
  2321.         mov     es, ax
  2322.         ; past most significant portion of the number
  2323.         mov     si, word ptr n              ; load pointers ds:si
  2324.         add     si, cx
  2325.         lds     di, r                       ; ds:di
  2326.         add     di, cx
  2327.  
  2328.         cmp     cpu, 386                ; check cpu
  2329.         je      use_32_bit              ; use faster 32 bit code if possible
  2330.  
  2331.         ; no need to clear r here, values get mov'ed, not add'ed
  2332.         shr     cx, 1                   ; byte = 1/2 word
  2333.         mov     bx, es:u
  2334.  
  2335.         ; need to start with most significant portion of the number
  2336.         sub     si, 2                   ; most sig word
  2337.         sub     di, 2                   ; most sig word
  2338.  
  2339.         sub     dx, dx                  ; clear dx register
  2340.                                         ; for first time through loop
  2341. top_loop_16:
  2342.         mov     ax, [si]                ; load next word from n
  2343.         div     bx
  2344.         mov     [di], ax                ; store low word
  2345.                                         ; leave remainder in dx
  2346.  
  2347.         sub     si, 2                   ; next word in n
  2348.         sub     di, 2                   ; next word in r
  2349.         loop    top_loop_16
  2350.         jmp     bottom
  2351.  
  2352. use_32_bit:
  2353. .386
  2354.         ; no need to clear r here, values get mov'ed, not add'ed
  2355.         shr     cx, 2                   ; byte = 1/4 dword
  2356.         sub     ebx, ebx                ; clear upper word or ebx
  2357.         mov     bx, es:u
  2358.  
  2359.         ; need to start with most significant portion of the number
  2360.         sub     si, 4                   ; most sig dword
  2361.         sub     di, 4                   ; most sig dword
  2362.  
  2363.         sub     edx, edx                ; clear edx register
  2364.                                         ; for first time through loop
  2365. top_loop_32:
  2366.         mov     eax, [si]               ; load next dword from n
  2367.         div     ebx
  2368.         mov     [di], eax               ; store low dword
  2369.                                         ; leave remainder in edx
  2370.  
  2371.         sub     si, 4                   ; next dword in n
  2372.         sub     di, 4                   ; next dword in r
  2373.         loop    top_loop_32
  2374.  
  2375. bottom:
  2376. .8086
  2377.  
  2378.         mov     ax, es                  ; swap es & ds
  2379.         mov     bx, ds
  2380.         mov     ds, ax
  2381.         mov     es, bx
  2382.  
  2383.         cmp     sign, 0                 ; is result + or - ?
  2384.         je      pos_answer              ; yes
  2385.         invoke  neg_a_bn, r             ; does not affect ES
  2386. pos_answer:
  2387.  
  2388.         mov     dx, es                  ; return r in dx:ax
  2389.         mov     ax, word ptr r          ;
  2390.         ret
  2391. unsafe_div_bn_int   ENDP
  2392.  
  2393. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2394. ; r /= u  where u is an unsigned integer
  2395. div_a_bn_int   PROC USES di, r:bn_t, u:word
  2396. LOCAL  sign:byte
  2397.  
  2398.         les     bx, r                       ; check for sign bits
  2399.         add     bx, bnlength
  2400.         dec     bx
  2401.         mov     al, es:[bx]
  2402.         and     al, 80h                     ; check the sign bit
  2403.         mov     sign, al
  2404.         jz      already_pos
  2405.         invoke  neg_a_bn, r
  2406. already_pos:
  2407.  
  2408.         mov     cx, bnlength            ; set outer loop counter
  2409.         mov     ax, ds                  ; save ds in es
  2410.         mov     es, ax
  2411.         lds     di, r                   ; load pointer r in ds:di
  2412.         add     di, cx
  2413.  
  2414.  
  2415.         cmp     cpu, 386                ; check cpu
  2416.         je      use_32_bit              ; use faster 32 bit code if possible
  2417.  
  2418.         ; no need to clear r here, values get mov'ed, not add'ed
  2419.         shr     cx, 1                   ; byte = 1/2 word
  2420.         mov     bx, es:u
  2421.  
  2422.         ; need to start with most significant portion of the number
  2423.         sub     di, 2                   ; most sig word
  2424.  
  2425.         sub     dx, dx                  ; clear dx register
  2426.                                         ; for first time through loop
  2427. top_loop_16:
  2428.         mov     ax, [di]                ; load next word from r
  2429.         div     bx
  2430.         mov     [di], ax                ; store low word
  2431.                                         ; leave remainder in dx
  2432.  
  2433.         sub     di, 2                   ; next word in r
  2434.         loop    top_loop_16
  2435.         jmp     bottom
  2436.  
  2437. use_32_bit:
  2438. .386
  2439.         ; no need to clear r here, values get mov'ed, not add'ed
  2440.         shr     cx, 2                   ; byte = 1/4 dword
  2441.         sub     ebx, ebx                ; clear upper word or ebx
  2442.         mov     bx, es:u
  2443.  
  2444.         ; need to start with most significant portion of the number
  2445.         sub     di, 4                   ; most sig dword
  2446.  
  2447.         sub     edx, edx                ; clear edx register
  2448.                                         ; for first time through loop
  2449. top_loop_32:
  2450.         mov     eax, [di]               ; load next dword from r
  2451.         div     ebx
  2452.         mov     [di], eax               ; store low dword
  2453.                                         ; leave remainder in edx
  2454.  
  2455.         sub     di, 4                   ; next dword in r
  2456.         loop    top_loop_32
  2457.  
  2458. bottom:
  2459. .8086
  2460.         mov     ax, es                  ; swap es & ds
  2461.         mov     bx, ds
  2462.         mov     ds, ax
  2463.         mov     es, bx
  2464.  
  2465.         cmp     sign, 0                 ; is result + or - ?
  2466.         je      pos_answer              ; yes
  2467.         invoke  neg_a_bn, r             ; does not affect ES
  2468. pos_answer:
  2469.  
  2470.         mov     dx, es                  ; return r in dx:ax
  2471.         mov     ax, word ptr r          ;
  2472.         ret
  2473. div_a_bn_int   ENDP
  2474.  
  2475. END
  2476.